梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
本教程将从 C++ 结构体的特性、定义、使用到进阶技巧,全面拆解 C++ 结构体的核心用法,帮助你掌握这一基础且重要的编程工具。
C++ 中的结构体(struct)是一种用户自定义复合数据类型,它不仅能封装多个不同类型的成员变量(数据),还能封装操作这些数据的成员函数(行为),是面向对象编程(OOP)中 “封装” 特性的重要载体。
| 特点 | C 语言结构体 | C++ 结构体 |
|---|---|---|
| 成员类型 | 仅支持成员变量(数据) | 支持成员变量 + 成员函数(数据 + 行为) |
| 访问权限 | 无访问权限控制(默认公开) | 支持public/private/protected(默认public) |
| 面向对象特性 | 不支持(无构造 / 析构函数) | 支持(构造、析构、继承、多态等) |
| 赋值与使用 | 仅数据拷贝 | 支持对象赋值、函数调用等完整操作 |
C++ 中struct和class的功能几乎完全一致,唯一核心区别是默认访问权限:
除此之外,两者都支持构造函数、析构函数、继承、虚函数等面向对象特性。
包含成员变量和成员函数:
struct 结构体名 {
// 访问权限修饰符(可选,默认public)
访问权限(public/private/protected):
// 成员变量(数据成员)
数据类型 成员变量1;
数据类型 成员变量2;
// ... 更多成员变量
// 成员函数(成员方法,分为声明+实现)
返回值类型 成员函数名1(参数列表);
返回值类型 成员函数名2(参数列表);
// ... 更多成员函数
};
// 结构体成员函数的外部实现(若内部仅声明)
返回值类型 结构体名::成员函数名(参数列表) {
// 函数体(可访问结构体的成员变量)
}
定义一个描述 “学生” 的结构体(包含成员变量和成员函数)
#include <iostream>
#include <cstring>
using namespace std;
// 定义Student结构体
struct Student {
// 成员变量(默认public,可直接访问)
char name[20]; // 姓名
int age; // 年龄
float score; // 成绩
// 成员函数:内部直接实现
void printInfo() {
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "成绩:" << score << endl;
}
// 成员函数:仅声明,外部实现
void updateScore(float newScore);
// 成员函数:带参数的初始化函数
void initStudent(const char* stuName, int stuAge, float stuScore) {
strcpy(name, stuName);
age = stuAge;
score = stuScore;
}
};
// 成员函数的外部实现(必须加"结构体名::"作用域解析符)
void Student::updateScore(float newScore) {
score = newScore;
cout << "成绩已更新为:" << newScore << endl;
}
C++ 支持多种结构体对象(实例)的创建和初始化方式,核心包括直接创建、构造函数初始化等。
#include <iostream>
#include <cstring>
using namespace std;
int main() {
// 创建Student对象
Student stu1;
// 直接访问成员变量赋值(因默认public,可直接修改)
strcpy(stu1.name, "张三");
stu1.age = 18;
stu1.score = 92.5;
// 调用成员函数
cout << "stu1信息:" << endl;
stu1.printInfo();
// 更新成绩并再次打印
stu1.updateScore(95.0);
cout << "更新后stu1信息:" << endl;
stu1.printInfo();
return 0;
}
#include <iostream>
using namespace std;
int main() {
Student stu2;
// 调用自定义初始化函数,批量设置成员变量
stu2.initStudent("李四", 19, 88.0);
cout << "\nstu2信息:" << endl;
stu2.printInfo();
return 0;
}
#include <iostream>
#include <cstring>
using namespace std;
// 重新定义带构造函数的Student结构体
struct Student {
// 成员变量
char name[20];
int age;
float score;
// 无参构造函数(默认构造函数)
Student() {
// 初始化默认值
strcpy(name, "未知姓名");
age = 0;
score = 0.0;
cout << "无参构造函数被调用" << endl;
}
// 有参构造函数(重载)
Student(const char* stuName, int stuAge, float stuScore) {
strcpy(name, stuName);
age = stuAge;
score = stuScore;
cout << "有参构造函数被调用" << endl;
}
// 成员函数
void printInfo() {
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "成绩:" << score << endl;
}
void updateScore(float newScore) {
score = newScore;
cout << "成绩已更新为:" << newScore << endl;
}
};
// 测试构造函数
int main() {
// 调用无参构造函数创建对象
Student stu3;
cout << "\nstu3默认信息:" << endl;
stu3.printInfo();
// 调用有参构造函数创建对象
Student stu4("王五", 20, 95.0);
cout << "\nstu4初始化信息:" << endl;
stu4.printInfo();
return 0;
}
根据对象的类型(普通对象 / 指针对象),使用不同的访问运算符:
语法:对象名.成员变量名 / 对象名.成员函数名(参数)
Student stu;
stu.age = 18; // 访问成员变量
stu.printInfo(); // 调用成员函数
语法:对象名.成员变量名 / 对象名.成员函数名(参数)
#include <iostream>
using namespace std;
int main() {
// 方式1:栈区对象取地址
Student stu5("赵六", 17, 90.0);
Student* pStu1 = &stu5;
// 通过指针访问成员
cout << "\n指针访问stu5信息:" << endl;
cout << "姓名:" << pStu1->name << endl;
pStu1->updateScore(92.0);
pStu1->printInfo();
// 方式2:堆区动态创建对象(new关键字)
Student* pStu2 = new Student("孙七", 21, 85.5);
cout << "\n堆区对象pStu2信息:" << endl;
pStu2->printInfo();
// 释放堆区内存(避免内存泄漏)
delete pStu2;
pStu2 = nullptr; // 避免野指针
return 0;
}
示例:带访问权限控制的结构体
#include <iostream>
#include <cstring>
using namespace std;
struct Student {
private:
// 私有成员变量:外部无法直接访问
char name[20];
int age;
float score;
public:
// 公有成员函数:作为外部访问私有成员的接口
Student(const char* stuName, int stuAge, float stuScore) {
strcpy(name, stuName);
age = stuAge;
score = stuScore;
}
void printInfo() {
// 内部可访问私有成员
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "成绩:" << score << endl;
}
void setAge(int newAge) {
// 可在函数内添加合法性校验
if (newAge > 0 && newAge < 100) {
age = newAge;
cout << "年龄已更新为:" << newAge << endl;
} else {
cout << "无效的年龄值!" << endl;
}
}
int getAge() {
return age;
}
};
int main() {
Student stu("周八", 19, 89.0);
stu.printInfo();
// stu.age = 20; // 错误:age是私有成员,外部无法直接访问
stu.setAge(20); // 正确:通过公有成员函数修改私有成员
cout << "当前年龄:" << stu.getAge() << endl;
stu.setAge(-5); // 非法值,会被函数拦截
return 0;
}
析构函数是与结构体同名、前缀加~的特殊成员函数,无参数、无返回值,用于对象销毁时自动释放资源(如堆区内存、文件句柄等),仅能有一个(无法重载)。
#include <iostream>
#include <cstring>
using namespace std;
struct MyString {
// 成员变量
char* str; // 字符指针,指向堆区字符串
// 构造函数:动态分配内存
MyString(const char* s) {
int len = strlen(s) + 1;
str = new char[len]; // 堆区分配内存
strcpy(str, s);
cout << "构造函数:分配内存,字符串为:" << str << endl;
}
// 析构函数:释放堆区内存
~MyString() {
delete[] str; // 释放数组内存
str = nullptr;
cout << "析构函数:释放内存" << endl;
}
// 成员函数
void printStr() {
cout << "字符串内容:" << str << endl;
}
};
int main() {
MyString strObj("Hello C++ Struct!");
strObj.printStr();
// 对象销毁时,析构函数会自动调用,无需手动释放
return 0;
}
结构体数组用于批量存储同类型结构体对象,便于统一管理和遍历。
#include <iostream>
using namespace std;
int main() {
// 定义结构体数组并通过有参构造函数初始化
Student stuArr[3] = {
Student("张三", 18, 92.5),
Student("李四", 19, 88.0),
Student("王五", 20, 95.0)
};
// 遍历结构体数组
cout << "\n学生列表:" << endl;
for (int i = 0; i < 3; i++) {
cout << "\n第" << i+1 << "个学生:" << endl;
stuArr[i].printInfo();
}
// 修改数组中对象的属性
stuArr[1].setAge(21);
cout << "\n修改后第2个学生年龄:" << stuArr[1].getAge() << endl;
return 0;
}
C++ 支持结构体对象作为函数的参数和返回值,推荐使用指针或引用传递(避免对象拷贝的性能开销)。
#include <iostream>
using namespace std;
// 值传递:会拷贝整个对象
void printStudent(Student stu) {
cout << "\n函数内打印学生信息:" << endl;
stu.printInfo();
}
int main() {
Student stu("赵六", 17, 90.0);
printStudent(stu);
return 0;
}
#include <iostream>
#include <cstring>
using namespace std;
// 引用传递:直接操作原对象,无拷贝开销
void updateStudentScore(Student& stu, float newScore) {
stu.updateScore(newScore);
}
// 指针传递:同样无拷贝开销
void printStudentByPtr(Student* pStu) {
cout << "\n指针传递打印学生信息:" << endl;
pStu->printInfo();
}
int main() {
Student stu("孙七", 21, 85.5);
updateStudentScore(stu, 89.0);
printStudentByPtr(&stu);
return 0;
}
#include <iostream>
using namespace std;
// 返回结构体对象
Student createStudent(const char* name, int age, float score) {
return Student(name, age, score);
}
int main() {
Student stu = createStudent("周八", 19, 88.0);
cout << "\n创建的学生信息:" << endl;
stu.printInfo();
return 0;
}
自引用结构体是指结构体内部包含一个指向自身结构体类型的指针成员,是实现链表、树、图等链式/层级数据结构的核心基础。
💡 核心原理:
不能直接在结构体中定义自身类型的成员变量(会导致无限递归定义,编译器无法确定结构体大小),但可以定义自身类型的指针(指针大小固定,仅占4/8字节)。
// 定义单向链表节点的自引用结构体
struct ListNode {
// 数据域:存储节点数据
int val;
// 指针域:指向同类型结构体的指针(自引用核心)
ListNode* next;
// 构造函数(简化初始化)
ListNode(int value) : val(value), next(nullptr) {
cout << "节点创建,值为:" << val << endl;
}
// 析构函数:释放后续节点内存(避免内存泄漏)
~ListNode() {
cout << "节点销毁,值为:" << val << endl;
// 递归释放后续节点
if (next != nullptr) {
delete next;
next = nullptr;
}
}
// 成员函数:遍历链表并打印
void printList() {
ListNode* current = this; // 从当前节点开始遍历
while (current != nullptr) {
cout << current->val << " -> ";
current = current->next;
}
cout << "nullptr" << endl;
}
// 成员函数:在链表尾部添加新节点
void addNode(int value) {
ListNode* current = this;
// 找到链表最后一个节点
while (current->next != nullptr) {
current = current->next;
}
// 创建新节点并挂载到尾部
current->next = new ListNode(value);
}
};
#include <iostream>
using namespace std;
int main() {
// 1. 创建链表头节点
ListNode* head = new ListNode(10);
// 2. 向链表尾部添加节点
head->addNode(20);
head->addNode(30);
head->addNode(40);
// 3. 遍历并打印链表
cout << "链表内容:";
head->printList();
// 4. 修改节点数据
head->next->val = 25; // 修改第二个节点的值
cout << "修改后链表:";
head->printList();
// 5. 释放链表内存(析构函数会递归释放所有节点)
delete head;
head = nullptr;
return 0;
}
本教程从 C++ 结构体的特性、定义、使用到进阶技巧,全面拆解 C++ 结构体的核心用法。掌握结构体的运用,是学习数据结构的重要基础之一。